import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:netease_cloud_music_api/utils/crypto.dart';
import 'package:netease_cloud_music_api/utils/player_request.dart';
import 'package:netease_cloud_music_api/utils/request.dart';

mixin Upload {

  Future<PlayerRequestResponse> _avatarUploadResult1({required String fileName}) {
    Map<String, dynamic> data = {
      'bucket': 'yyimgs',
      'ext': 'jpg',
      'filename': fileName,
      'local': false,
      'nos_product': 0,
      'return_body': '{"code":200,"size":"\$(ObjectSize)"}',
      'type': 'other'
    };
    return PlayerRequest(
      url: 'https://music.163.com/weapi/nos/token/alloc',
      data: data,
      options: PlayerRequestOptions(method: PlayerRequestMethod.post, crypto: EncryptType.weapi),
    ).request();
  }

  Future<HttpClientResponse> _avatarUploadResult2({required String token, required String? objectKey, required Uint8List imageData}) async {
    HttpClient httpClient = HttpClient();
    String url = 'http://nosup-hz1.127.net/yyimgs/$objectKey?offset=0&complete=true&version=1.0';
    var request = await httpClient.postUrl(Uri.parse(url));
    request.headers.add('x-nos-token', token);
    request.headers.add('HttpHeaders.contentTypeHeader', 'image/jpeg');
    request.write(String.fromCharCodes(imageData));
    var response = await request.close();
    var data = '';
    if (response.statusCode == HttpStatus.ok) {
      await for (var contents in response) {
        data += String.fromCharCodes(contents);
      }
    }
    print(data);
    return response;
  }

  Future<PlayerRequestResponse> _avatarUploadResult3({String? imgSize, String? imgX, String? imgY, required String? docId}) async {
    return await PlayerRequest(
      url: 'https://music.163.com/upload/img/op?id=$docId&op=${imgX ?? 0}y${imgY ?? 0}y${imgSize ?? 300}y${imgSize ?? 300}',
      options: PlayerRequestOptions(
        method: PlayerRequestMethod.post,
        crypto: EncryptType.weapi,
      ),
    ).request();
  }

  Future<PlayerRequestResponse> avatarUpload({required String fileName, required Uint8List imageData, String? imgSize, String? imgX, String? imgY}) async {
    try {
      PlayerRequestResponse response1 = await _avatarUploadResult1(fileName: fileName);
      Map<String, dynamic> result1 = jsonDecode(response1.body)['result'];
      await _avatarUploadResult2(
        token: result1['token'],
        objectKey: result1['objectKey'],
        imageData: imageData,
      );
      PlayerRequestResponse response3 = await _avatarUploadResult3(
        docId: result1['docId'],
        imgSize: imgSize ?? '1012',
        imgX: imgX ?? '0',
        imgY: imgY ?? '0',
      );
      Map<String, dynamic> result3 = jsonDecode(response3.body);
      PlayerRequestResponse response = await PlayerRequest(
        url: 'https://music.163.com/weapi/user/avatar/upload/v1',
        data: {'imgid': result3['id']},
        options: PlayerRequestOptions(method: PlayerRequestMethod.post, crypto: EncryptType.weapi),
      ).request();

      return PlayerRequestResponse(status: response.status, body: {
        'url_pre': "https://p1.music.126.net/${result1['objectKey']}",
        'url': result3['url'],
        'imgId': result3['id'],
        ...jsonDecode(response.body),
      }, cookie: response.cookie);
    } catch (e) {
      if (e is DioError) {
        print(e.response);
        return PlayerRequestResponse(body: e);
      } else {
        print(e);
        return PlayerRequestResponse();
      }
    }
  }

  Future<PlayerRequestResponse> playlistCoverUpload({required int playlistId, required String fileName, required Uint8List imageData, String? imgSize, String? imgX, String? imgY}) async {
    try {
      PlayerRequestResponse response1 = await _avatarUploadResult1(fileName: fileName);
      Map<String, dynamic> result1 = jsonDecode(response1.body)['result'];
      await _avatarUploadResult2(
        token: result1['token'],
        objectKey: result1['objectKey'],
        imageData: imageData,
      );
      print(result1);
      PlayerRequestResponse response3 = await _avatarUploadResult3(
        docId: result1['docId'],
        imgSize: imgSize ?? '1012',
        imgX: imgX ?? '0',
        imgY: imgY ?? '0',
      );
      Map<String, dynamic> result3 = jsonDecode(response3.body);
      print(result3);
      PlayerRequestResponse response = await PlayerRequest(
        url: 'https://music.163.com/weapi/playlist/cover/update',
        data: {'coverImgId': result3['id'], 'id': playlistId},
        options: PlayerRequestOptions(method: PlayerRequestMethod.post, crypto: EncryptType.weapi),
      ).request();

      return PlayerRequestResponse(status: response.status, body: {
        'url_pre': "https://p1.music.126.net/${result1['objectKey']}",
        'url': result3['url'],
        'imgId': result3['id'],
        ...jsonDecode(response.body),
      }, cookie: response.cookie);
    } catch (e) {
      if (e is DioError) {
        print(e.response);
        return PlayerRequestResponse(body: e);
      } else {
        print(e);
        return PlayerRequestResponse();
      }
    }
  }
}
